//
//  1143_最长公共子序列.swift
//  Swift-LeetCode
//
//  Created by 卢悦明 on 2024/3/5.
/**
 给定两个字符串 text1 和 text2，返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ，返回 0 。

 一个字符串的 子序列 是指这样一个新的字符串：它是由原字符串在不改变字符的相对顺序的情况下删除某些字符（也可以不删除任何字符）后组成的新字符串。

 例如，"ace" 是 "abcde" 的子序列，但 "aec" 不是 "abcde" 的子序列。
 两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
 示例 1：
 输入：text1 = "abcde", text2 = "ace" 公共子序列“ace”
 输出：3
 解释：最长公共子序列是 "ace" ，它的长度为 3 。
 
 示例 2：
 输入：text1 = "abc", text2 = "abc"
 输出：3
 解释：最长公共子序列是 "abc" ，它的长度为 3 。
 
 示例 3：
 输入：text1 = "abc", text2 = "def"
 输出：0
 解释：两个字符串没有公共子序列，返回 0 。
 */

import UIKit
// 动态规划实现（pd[i][j]以numb数组中前i,j个元素的最长公共子串长度）
class GetLongestCommonSubsequence: NSObject {
    func QA() {
        print( longestCommonSubsequence1("abcde", "ace") == longestCommonSubsequence("abcde", "ace"))
        print( longestCommonSubsequence1("abc", "abc") == longestCommonSubsequence("abc", "abc"))
        print( longestCommonSubsequence1("abc", "def") == longestCommonSubsequence("abc", "def"))
        print( longestCommonSubsequence1("abcba", "abcbcba") == longestCommonSubsequence("abcba", "abcbcba"))

    }
    func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int {
        if text1.count == 0 || text2.count == 0 {
            return 0
        }
        let Array1 = Array(text1)
        let Array2 = Array(text2)
        let count1 = text1.count
        let count2 = text2.count
        //        Array(repeating: Array(repeating: 0, count: count2 + 1), count: count1 + 1)

        var dp = [[Int]](repeating: [Int](repeating: 0, count: count2 + 1), count: count1 + 1)
        
        for i in 1...count1 {
            for j in 1...count2 {
                if Array1[i-1] == Array2[j-1] {
                    dp[i][j] = dp[i-1][j-1] + 1
                } else {
                    dp[i][j] = max(dp[i-1][j], dp[i][j-1])
                }
            }
        }
        return dp[count1][count2]
    }
    
    /// 优化空间复杂度
    func longestCommonSubsequence1(_ text1: String, _ text2: String) -> Int {
        if text1.count == 0 || text2.count == 0 {
            return 0
        }
        let Array1 = Array(text1)
        let Array2 = Array(text2)
        let count1 = text1.count
        let count2 = text2.count
        var dp = Array(repeating: 0, count: count2 + 1)
        
        for i in 1...count1 {
            var current = 0
            for j in 1...count2 {
                let leftTop = current
                current = dp[j]
                if Array1[i-1] == Array2[j-1] {
                    dp[j] = leftTop + 1
                } else {
                    let top = dp[j]
                    let left = dp[j-1]
                    dp[j] = max(top, left)
                }
            }
        }
        return dp[count2]
    }
        
}
